package com.zhu.wx.controller;

import com.google.gson.Gson;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.SHA1;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import com.zhu.wx.dict.WxEventEnum;
import com.zhu.wx.dict.WxRecEnum;
import com.zhu.wx.dict.WxResEnum;
import com.zhu.wx.entity.ResMsg;
import com.zhu.wx.facade.RecStrategyFacade;
import com.zhu.wx.facade.ResStrategyFacade;
import com.zhu.wx.util.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@RestController
public class IndexController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${wx.token}")
    private String wxToken;
    @Value("${wx.appid}")
    private String wxAppid;
    @Value("${wx.aeskey}")
    private String wxAeskey;

    /**
     * 验证签名
     * 参数	描述
     * signature	微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
     * timestamp	时间戳
     * nonce	随机数
     * echostr	随机字符串
     *
     * @return
     */
    @GetMapping("/verify_wx_token")
    public String get(String signature, String timestamp, String nonce, String echostr) {
        logger.info("GET------------------------");
        logger.info("signature = " + signature);
        logger.info("timestamp = " + timestamp);
        logger.info("nonce = " + nonce);
        logger.info("echostr = " + echostr);
        if (CRYPT) {
            try {
                //encrypt 密文为空
                String sha1 = SHA1.getSHA1(wxToken, timestamp, nonce, "");
                logger.info("sha1 = " + sha1);
                if (sha1.equalsIgnoreCase(signature)) {
                    return echostr;
                }
            } catch (AesException e) {
                e.printStackTrace();
            }
        }
        return "success";
    }

    @Autowired
    RecStrategyFacade recStrategyFacade;
    @Autowired
    ResStrategyFacade resStrategyFacade;

    /**
     * 是否加密
     */
    private final static Boolean CRYPT = true;

    /**
     * 公众号调用接口
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/verify_wx_token")
    public String handler(HttpServletRequest request) throws Exception {
        logger.info("POST------------------------");
        if (CRYPT) {
            return handleWithCrypt(request);
        } else {
            return handleWithNoCrypt(request);
        }
    }

    /**
     * 加密处理
     *
     * @param request
     * @return
     * @throws Exception
     */
    private String handleWithCrypt(HttpServletRequest request) throws Exception {
        request.setCharacterEncoding("UTF-8");
        //获取postdata
        ServletInputStream inputStream = request.getInputStream();
        StringBuilder content = new StringBuilder();
        byte[] b = new byte[1024];
        int lens;
        while ((lens = inputStream.read(b)) > 0) {
            content.append(new String(b, 0, lens));
        }
        String postdata = content.toString();
        // postdata
        WXBizMsgCrypt crypt = new WXBizMsgCrypt(wxToken, wxAeskey, wxAppid);
        String signature = request.getParameter("msg_signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        logger.info("signature = " + signature);
        logger.info("timestamp = " + timestamp);
        logger.info("nonce = " + nonce);
        logger.info("postdata = " + postdata);
        //解密数据
        String decryptMsg = crypt.decryptMsg(signature, timestamp, nonce, postdata);
        InputStream stream = new ByteArrayInputStream(decryptMsg.getBytes(StandardCharsets.UTF_8));
        Map<String, String> parseXml = XmlUtil.xmlToMap(stream);
        //执行业务获取返回
        String replyMsg = getReplyMsg(parseXml);
        //加密回复
        return crypt.encryptMsg(replyMsg, timestamp, nonce);
    }

    /**
     * 明文处理
     *
     * @param request
     * @return
     * @throws Exception
     */
    private String handleWithNoCrypt(HttpServletRequest request) throws Exception {
        request.setCharacterEncoding("UTF-8");
        Map<String, String> parseXml = XmlUtil.xmlToMap(request.getInputStream());
        //执行业务获取返回
        return getReplyMsg(parseXml);
    }

    private String getReplyMsg(Map<String, String> parseXml) {
        logger.info(new Gson().toJson(parseXml));
        String msgType = parseXml.get("MsgType");
        if (StringUtils.isEmpty(msgType)) {
            logger.error("MsgType为空");
            return "";
        }
        //参数结果查询
        WxRecEnum wxRecEnum;
        try {
            wxRecEnum = WxRecEnum.valueOf(msgType.toUpperCase());
        } catch (Exception e) {
            logger.error("未找到枚举{}", msgType);
            return "";
        }
        ResMsg resMsg;
        //是否是事件推送
        if (WxRecEnum.EVENT.equals(wxRecEnum)) {
            String event = parseXml.get("Event");
            if (StringUtils.isEmpty(event)) {
                logger.error("Event为空");
                return "";
            }
            WxEventEnum wxEventEnum;
            try {
                wxEventEnum = WxEventEnum.valueOf(event.toUpperCase());
            } catch (Exception e) {
                logger.error("未找到枚举{}", event);
                return "";
            }
            resMsg = recStrategyFacade.execute(parseXml, wxEventEnum);
        } else {
            resMsg = recStrategyFacade.execute(parseXml, wxRecEnum);
        }
        if (resMsg == null) {
            logger.error("无对应数据----");
            return "";
        }
        //结果返回处理
        WxResEnum wxResEnum;
        try {
            wxResEnum = WxResEnum.valueOf(resMsg.getMsgType().toUpperCase());
        } catch (Exception e) {
            logger.error("未找到枚举{}", resMsg.getMsgType());
            return "";
        }
        return resStrategyFacade.execute(resMsg, wxResEnum);
    }
}
